﻿using AlarmModule;
using AlarmModule.DbContexts;
using AlarmModule.Enums;
using AlarmModule.Interface.Implementation;
using AlarmModule.Models;
using AlarmModule.Utils;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LiveCharts;
using LiveCharts.Wpf;
using LoginModule.Models;
using LogModule.Interface;
using Modbus.Device;
using MonitorModule.DbContexts;
using MonitorModule.Models;
using Prism.Dialogs;
using Prism.Navigation;
using Prism.Navigation.Regions;
using StaffModule.DbContexts;
using StaffModule.Models;
using StaffModule.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using WorkshopModule.DbContexts;
using WorkshopModule.Enums;
using WorkshopModule.Models;
using WorkshopModule.Tools;
using WorkshopModule.Views;
using Timer = System.Timers.Timer;

namespace MonitorModule.ViewModels {
    public partial class MonitorUCViewModel : ObservableObject, INavigationAware {

        #region 画图字段
        [ObservableProperty]
        private SeriesCollection _seriesCollection = new();//折线图

        [ObservableProperty]
        private List<string> _labels;//横坐标

        private double _trend;

        private double[] temp = { 1, 3, 2, 4, -3, 5, 2, 1 };

        #endregion

        #region 集合属性

        //报警,线程安全字典
        [ObservableProperty]
        private Dictionary<string, AlarmParameter> _parameters = new();//报警参数

        /// <summary>
        /// 环境监控数据
        /// </summary>
        [ObservableProperty]
        private ObservableCollection<AlarmParameter> _enviromentList = new();


        /// <summary>
        /// 报警集合
        /// </summary>
        /// 
        [ObservableProperty]
        private ObservableCollection<AlarmModel> _alarmList = new();


        /// <summary>
        /// 设备集合
        /// </summary>
        /// 
        [ObservableProperty]
        private ObservableCollection<AlarmParameter> _deviceList = new();


        /// <summary>
        /// 雷达
        /// </summary>
        /// 
        [ObservableProperty]
        private ObservableCollection<RaderModel> _raderList = new();


        /// <summary>
        /// 缺岗员工
        /// </summary>
        /// 
        [ObservableProperty]
        private ObservableCollection<StuffOutWorkModel> _stuffOutWorkList = new();

        /// <summary>
        /// 员工
        /// </summary>
        /// 
        [ObservableProperty]
        private ObservableCollection<StaffDetails> _staffDetailsList = new();



        /// <summary>
        /// 车间
        /// </summary>
        /// 
        [ObservableProperty]
        private ObservableCollection<WorkShopModel> _workShopList = new();



        /// <summary>
        /// 缺岗
        /// </summary>
        [ObservableProperty]
        private ObservableCollection<Vacancy> _vacancyList = new();



        #endregion

        #region 其它属性
        [ObservableProperty]
        private AccountInfoModel? _accountInfoModel = new();
        public DialogCloseListener RequestClose { get; set; }
        public string Title { get; set; } = " ";
        #endregion

        #region 时间
        private DispatcherTimer _timer;
        private void Timer_Tick(object sender, EventArgs e) {
            var now = DateTime.Now;
            TimeStr = now.ToString("HH:mm");     // 触发set方法
            DateStr = now.ToString("yyyy-MM-dd");
            WeekStr = week[(int)now.DayOfWeek];  // 直接根据最新时间计算星期
        }


        [ObservableProperty]
        private string _timeStr;


        [ObservableProperty]
        private string _dateStr;

        static string[] week = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };


        [ObservableProperty]
        private string _weekStr;
        #endregion

        #region 计数字段
        /// <summary>
        /// 机台总数
        /// </summary>
        [ObservableProperty]
        private string _machineCount = "0";

        /// <summary>
        /// 生产计数
        /// </summary>
        [ObservableProperty]
        private string _productCount = "0";

        /// <summary>
        /// 不良计数
        /// </summary>
        [ObservableProperty]
        private string _badCount = "0";

        //心跳定时器
        private Timer _heartbeatTimer;

        private const int HeartbeatInterval = 2000;//心跳周期(ms)

        private ModbusSerialMaster master;

        private SerialPort serialPort;

        //重连次数
        const int MAX_RETRY = 5;  // 最大重试次数


        [ObservableProperty]
        private AlarmEngine _engine;//需要传参,在构造函数中new

        [ObservableProperty]
        private AlarmCenter _alarmCenter;

        #endregion

        #region 依赖注入属性
        //区域管理:依赖注入取出
        private readonly IRegionManager RegionManager;

        // 对话框服务
        private readonly IDialogService DialogService;

        //日志
        private readonly ILogService _logger;

        //数据库上下文
        private readonly WorkshopDbContext WorkshopDbContext;

        private readonly MonitorDbContext MonitorDbContext;

        private readonly StaffDbContext StaffDbContext;

        private readonly AlarmDbContext DbContext;

        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="_RegionManager"></param>
        /// <param name="_WorkshopDbContext"></param>
        /// <param name="_MonitorDbContext"></param>
        /// <param name="_staffDbContext"></param>
        public MonitorUCViewModel(LogAlarmNotifier logAlarmNotifier, AlarmDbContext dbContext, ILogService logger, IRegionManager regionManager, WorkshopDbContext workshopDbContext, MonitorDbContext monitorDbContext, StaffDbContext staffDbContext, IDialogService dialogService) {

            #region 画图
            LineSeries mylineseries = new LineSeries();//实例化一条折线图
            mylineseries.Title = "质量";//设置折线的标题
            mylineseries.LineSmoothness = 0;//折线图直线形式
            mylineseries.PointGeometry = null;//折线图的无点样式
            Labels = new List<string> { "1", "3", "2", "4", "-3", "5", "2", "1" };//添加横坐标,初始横坐标   
            mylineseries.Values = new ChartValues<double>(temp);//添加纵坐标数据，初始纵坐标
            //SeriesCollection = new SeriesCollection { };
            SeriesCollection.Add(mylineseries);
            //_trend = 8;
            linestart();
            #endregion

            #region 依赖注入

            DbContext = dbContext;

            DialogService = dialogService;

            _logger = logger;

            logger.Info("监控模块初始化");

            WorkshopDbContext = workshopDbContext;

            MonitorDbContext = monitorDbContext;

            StaffDbContext = staffDbContext;

            RegionManager = regionManager;

            #endregion

            #region 报警相关
            //(Key值,报警参数配置类)
            _parameters = monitorDbContext.AlarmParameter.ToDictionary(x => x.KeyName, x => x);

            // 创建报警引擎与中心
            _engine = new AlarmEngine(_parameters);//报警引擎,将评判标准给报警引擎
            _alarmCenter = new AlarmCenter();//报警中心
            _alarmCenter.Subscribe(logAlarmNotifier);//报警中心添加订阅者,订阅者有报警处理器

            #endregion

            #region 时间更新
            //初始化
            var now = DateTime.Now;
            TimeStr = now.ToString("HH:mm");
            DateStr = now.ToString("yyyy-MM-dd");
            WeekStr = week[(int)now.DayOfWeek];

            // 初始化定时器
            _timer = new DispatcherTimer();//new一个对象
            _timer.Interval = TimeSpan.FromSeconds(10);//间隔时间
            _timer.Tick += Timer_Tick;//事件绑定事件处理器(方法)
            _timer?.Start();
            #endregion

            #region 初始化环境监控数据

            EnviromentList = MonitorDbContext.AlarmParameter.Where(x => x.Type == 1)?.ToList().ToObservableCollection();


            // 初始化一次
            serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);//串口
            master = ModbusSerialMaster.CreateRtu(serialPort);//Modbus RTU
            master.Transport.ReadTimeout = 2000; // 2秒超时
            master.Transport.WriteTimeout = 2000; // 添加写超时设置

            // 使用 CancellationTokenSource 取消操作控制器: ​​生成和管理取消令牌
            var cts = new CancellationTokenSource();
            var ctsToken = cts.Token;//取消令牌

            // 启动异步循环
            //Task.Factory.StartNew(() => RunModbusLoopAsync(ctsToken, master, serialPort, 1, 0, 8, EnviromentList),
            //    ctsToken, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap(); // 解包内层异步任务

            Task.Run(async() => {
               await RunModbusLoopAsync(ctsToken, master, serialPort, 1, 0, 8, EnviromentList);
            }, ctsToken);



            #endregion

            #region 初始化报警列表
            try {
                AlarmList = dbContext.AlarmModel.OrderByDescending(a => a.Time).Take(10).ToList().ToObservableCollection();
            } catch (Exception ex) {
                _logger.Error("初始化报警列表失败", ex);
            }
            #endregion

            #region 初始化设备监控

            DeviceList = MonitorDbContext.AlarmParameter.Where(x => x.Type == 0)?.ToList().ToObservableCollection();

            #region 从设备读取设备数据
            // 初始化一次
            var serialPort1 = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
            var master1 = ModbusSerialMaster.CreateRtu(serialPort1);
            master1.Transport.ReadTimeout = 2000; // 2秒超时
            master1.Transport.WriteTimeout = 2000; // 添加写超时设置

            // 使用 CancellationTokenSource 取消操作控制器: ​​生成和管理取消令牌
            var cts1 = new CancellationTokenSource();
            var ctsToken1 = cts1.Token;//取消令牌

            // 启动异步循环
            //Task.Factory.StartNew(() => RunModbusLoopAsync(ctsToken1, master1, serialPort1, 2, 0, 9, DeviceList),
            //    ctsToken1, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap(); // 解包内层异步任务

            Task.Run(async() => {
                await RunModbusLoopAsync(ctsToken1, master1, serialPort1, 2, 0, 9, DeviceList);
            }, ctsToken1);

            #endregion

            #endregion

            #region 初始化雷达数据 
            RaderList = MonitorDbContext.RaderModel.ToList().ToObservableCollection();

            #endregion

            #region 初始化人员缺岗信息
            var query1 = from x in StaffDbContext.StaffDetails
                         join y in StaffDbContext.StuffOutWorkModel on x.Id equals y.Id
                         select new Vacancy { StuffName = x.Name, Position = EnumDependency.GetEnumDescription(x.Position), OutWorkCount = y.OutWorkCount, ShowWidth = y.ShowWidth };

            var list1 = query1.ToList();
            foreach (var item in list1) {
                VacancyList.Add(item);
            }
            #endregion

            #region 初始化车间列表 

            try {
                if (MonitorDbContext?.WorkShopModel == null || WorkshopDbContext?.DeviceDetail == null) {
                    _logger.Error("监控模块初始化车间列表数据库上下文未初始化");
                    throw new InvalidOperationException("数据库上下文未初始化");
                }
                var workShopModels = MonitorDbContext.WorkShopModel?.ToList() ?? new List<WorkShopModel>();
                var deviceDetails = WorkshopDbContext.DeviceDetail?.ToList() ?? new List<DeviceDetail>();
                foreach (var item in workShopModels) {
                    var query = deviceDetails.Where((x) => x.WorkShopId == item.WorkShopId);
                    int Work = query.Where((x) => x.DeviceStatus == DeviceStatus.Work).Count();
                    int Wait = query.Where((x) => x.DeviceStatus == DeviceStatus.Wait).Count();
                    int Halt = query.Where((x) => x.DeviceStatus == DeviceStatus.Halt).Count();
                    int Breakdown = query.Where((x) => x.DeviceStatus == DeviceStatus.Breakdown).Count();
                    item.StopCount = Halt;
                    item.WaitCount = Wait;
                    item.WrongCount = Breakdown;
                    item.WorkingCount = Work;
                    item.TotalCount = item.WorkingCount + item.WaitCount + item.StopCount + item.WrongCount;
                    WorkShopList.Add(item);
                }
            } catch (Exception ex) {
                //记录日志
                _logger.Error("初始化车间列表失败", ex);
            }
            #endregion

        }

        #region 画图
        //连续折线图的方法
        public void linestart() {
            Task.Run(async() => {
                var r = new Random();//随机函数
                while (true) {
                    await Task.Delay(1000);//刷新间隔时间
                    _trend = r.Next(-10, 10);//随机数产生y值
                    //通过Dispatcher在工作线程中更新窗体的UI元素
                   // Application.Current.Dispatcher.Invoke(() => {
                        //更新横坐标时间
                        Labels.Add(DateTime.Now.ToString());//添加横坐标时间数据值
                        Labels.RemoveAt(0);
                        //更新纵坐标数据
                        SeriesCollection[0].Values.Add(_trend);//添加y值，_trend为数据
                        SeriesCollection[0].Values.RemoveAt(0);
                 //   });
                }
            });
        }
        #endregion

        #region 方法
        [RelayCommand]
        private void ShowSettings() {
            //使用字典传输数据
            DialogParameters paras = new DialogParameters();//这是一个字典
            paras.Add("Title", "配置中心");//给对话框传数据
            paras.Add("EnviromentList", EnviromentList);
            paras.Add("DeviceList", DeviceList);
            //对话框服务,callback接收返回的参数
            DialogService.ShowDialog("Settings", paras,
                callback => {
                    if (callback.Result == ButtonResult.OK) {


                    }
                    if (callback.Result == ButtonResult.No) {

                    }
                });
        }

        private async Task AlarmListUpdate() {
            while (true) {
                try {
                    AlarmList = DbContext.AlarmModel.OrderByDescending(a => a.Time).Take(10).ToList().ToObservableCollection();
                } catch (Exception ex) {
                    _logger.Error("查询报警列表失败", ex);
                }
                await Task.Delay(10000);
            }
        }

        #region 环境监控数据相关函数
        /// <summary>
        /// 异步开启modbus
        /// </summary>
        /// <param name="cancellationToken">取消操作控制器: ​​生成和管理取消令牌</param>
        /// <param name="master">Modbus RTU</param>
        /// <param name="serialPort">串口</param>
        /// <param name="slaveAddress">从机地址</param>
        /// <param name="startAddress">开始地址</param>
        /// <param name="numberOfPoints"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        private async Task RunModbusLoopAsync(CancellationToken cancellationToken, ModbusSerialMaster master, SerialPort serialPort,
            byte slaveAddress, ushort startAddress, ushort numberOfPoints, ObservableCollection<AlarmParameter> list) {//1 , (0 , 8)  → 0-7
            int retryCount = 0;//重连次数

            if (!serialPort.IsOpen) {//判断串口是否开启,若关闭,则开启
                serialPort.Open();
            }

            while (!cancellationToken.IsCancellationRequested) {
                try {

                    #region 心跳机制
                    // 阶段1：读取当前值 V1
                    ushort v1 = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints)[numberOfPoints - 1];

                    // 阶段2：写入复位指令 (0xAAAA)
                    master.WriteSingleRegister(slaveAddress, Convert.ToUInt16(numberOfPoints - 1), 0);

                    // 等待复位生效（根据从机响应速度调整）
                    await Task.Delay(500);

                    // 阶段3：读取复位后值 V2
                    ushort v2 = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints)[numberOfPoints - 1];

                    // 验证逻辑（需从机配合：收到0xAAAA后立即复位计数器）
                    bool isAlive = v2 > 0 && v2 < 10; // 假设从机150ms内自增<10

                    if (!isAlive) {//如果心跳丢失
                        _logger.Error($"心跳丢失! 复位前:{v1} 复位后:{v2}");
                        throw new Exception($"心跳丢失! 复位前:{v1} 复位后:{v2}");
                    } else {//如果心跳恢复/心跳未丢失
                        //通信恢复重置(重连次数)计数器
                        retryCount = 0;
                    }
                    #endregion

                    // 异步读取寄存器（需支持异步的 Modbus 库）
                    ushort[] value = await master.ReadHoldingRegistersAsync(slaveAddress, startAddress, Convert.ToUInt16(numberOfPoints - 1));//从设备地址，寄存器起始地址，寄存器个数

                    // 获取T的类型,高频查询效率查
                    //Type tType = list.GetType().GetGenericArguments()[0];

                    for (int i = startAddress; i <= numberOfPoints - 2; i++) {

                        list[i].Value = value[i];

                        var level = Engine.CheckAlarm(list[i].KeyName, value[i]);//报警引擎根据评判标准给出报警水平

                        if (level != AlarmLevel.Normal) {//报警水平不正常,报警中心遍历所有订阅者处理警报
                            AlarmCenter.TriggerAlarm(list[i].TagName, level);
                        }
                    }

                    // 非阻塞等待
                    await Task.Delay(3000, cancellationToken);

                } catch (OperationCanceledException ocex) {
                    // 任务取消时的清理逻辑
                    break;
                } catch (Exception ex) {// 异步重连（需支持异步重连逻辑）

                    if (retryCount >= MAX_RETRY) {//1. 重连次数超了,不再重连
                        _logger.Error($"重连失败超过{MAX_RETRY}次，停止尝试");
                        MessageBox.Show("重连次数过限");
                        await HandlePermanentFailure(serialPort); // 自定义最终处理
                        break; // 关键：跳出循环
                    } else {//2. 重连次数没超,重连操作
                        //指数退避策略
                        int delay = Math.Min(1000 * (int)Math.Pow(2, retryCount), 10000);
                        await Task.Delay(delay).ConfigureAwait(false);
                        ++retryCount;//无论重连是否成功,都要+1

                        serialPort.DiscardInBuffer();//丢弃来自串行驱动程序的接收缓冲区的数据
                        serialPort.DiscardOutBuffer();//丢弃来自串行驱动程序的传输缓冲区的数据
                        if (await ReconnectSerialPortAsync(serialPort, cancellationToken)) {//分开写应该会混乱,因为异步
                            master = ModbusSerialMaster.CreateRtu(serialPort);//重建 ModbusSerialMaster 对象;依据：串口重连后需重新初始化协议栈                                          
                            master.Transport.ReadTimeout = 2000; // 2秒超时
                            master.Transport.WriteTimeout = 2000; // 添加写超时设置
                                                                 
                            _logger.Info("串口重启成功"); // 日志记录
                        } else {
                            _logger.Info("串口重启失败"); // 日志记录
                        }
                    }
                } finally {
                    // 取消任务且串口未关闭
                    if (cancellationToken.IsCancellationRequested && serialPort.IsOpen) {
                        serialPort.Close();
                        serialPort.Dispose();
                    }
                }
            }

        }
        /// <summary>
        /// 最终处理函数
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private async Task HandlePermanentFailure(SerialPort serialPort) {
            // 1. 关闭串口释放资源
            if (serialPort.IsOpen) {
                serialPort.Close();//关闭串口连接，清除接收缓冲区和传输缓冲区
                serialPort.Dispose();//释放由 SerialPort 占用的所有资源（包括托管和非托管资源）
            }
            await Task.Delay(100); // 延迟0.1秒,无意义的延迟
            // 2. 更新UI状态
            Application.Current.Dispatcher.Invoke(() => {

            });
        }

        /// <summary>
        /// 串口重启
        /// </summary>
        /// <param name="port"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public async Task<bool> ReconnectSerialPortAsync(SerialPort port, CancellationToken cancellationToken = default) {

            try {
                // 1. 异步关闭串口（避免阻塞 UI 线程）
                if (port.IsOpen) {
                    await Task.Run(() => port.Close(), cancellationToken).ConfigureAwait(false);
                }

                // 3. 异步打开串口（支持取消操作）
                bool IsOpen1 = await Task.Run(() => {
                    try {
                        port.Open();
                        //如果串口成功打开,则返回true,未成功返回false
                        return port.IsOpen;
                    } catch (UnauthorizedAccessException ex) {
                        _logger.Error("串口被占用或权限不足", ex);
                        return false;
                        throw new InvalidOperationException("串口被占用或权限不足", ex);
                    }
                }, cancellationToken).ConfigureAwait(false);

                return IsOpen1;//直接返回结果
            } catch (OperationCanceledException) {
                // 用户主动取消操作时退出

                return false;
            } catch (IOException ex) {

                // 物理连接异常处理,应该添加重连机制+日志记录

                // 轮询等待端口恢复
                while (!SerialPort.GetPortNames().Contains(port.PortName)) {
                    await Task.Delay(5000, cancellationToken);
                    if (cancellationToken.IsCancellationRequested) {
                        return false; // 支持取消
                    }

                }
                try {
                    if (!port.IsOpen) {
                        port.Open();
                    }
                    return true; // 重连成功
                } catch {
                    return false; // 打开失败
                }

            } catch (TimeoutException ex) {
                _logger.Error("监控方法:重连方法:重连串口超时", ex);
                // 超时处理
                return false;
            } catch (Exception ex) {
                // 4. 统一异常处理（记录日志或触发重试策略）
                _logger.Error("监控方法:重连方法:重连串口失败", ex);
                //串口重连失败
                return false;
            }
        }

        #endregion

        #endregion

        #region MainWindow的后台逻辑

        /// <summary>
        /// 显示车间详情页
        /// </summary>
        /// 
        [RelayCommand]
        private void ShowDetail(int? WorkShopId) {
            WorkShopDetailUC workShopDetailUC = new WorkShopDetailUC();

            //this.UserControlUC = workShopDetailUC;
            ShowDetailUCFunction(WorkShopId);

            // 动画效果(由下而上)
            //位移 移动时间
            ThicknessAnimation thicknessAnimation = new ThicknessAnimation(new Thickness(0, 50, 0, -50), new Thickness(0, 0, 0, 0), new TimeSpan(0, 0, 0, 0, 400));

            //透明度
            DoubleAnimation doubleAnimation = new DoubleAnimation(0, 1, new TimeSpan(0, 0, 0, 0, 400));

            Storyboard.SetTarget(thicknessAnimation, workShopDetailUC);
            Storyboard.SetTarget(doubleAnimation, workShopDetailUC);

            Storyboard.SetTargetProperty(thicknessAnimation, new PropertyPath("Margin"));
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));

            Storyboard storyboard = new Storyboard();
            storyboard.Children.Add(thicknessAnimation);
            storyboard.Children.Add(doubleAnimation);
            storyboard.Begin();
        }
        /// <summary>
        /// 转到车间模块
        /// </summary>
        /// <param name="WorkShopId"></param>
        private void ShowDetailUCFunction(int? WorkShopId) {

            //通过字典传输数据
            NavigationParameters paras = new NavigationParameters();//这是一个字典
            paras.Add("WorkShopId", WorkShopId);//给字典添加数据:键值对形式
            try {
                RegionManager.Regions["ContentRegion"].RequestNavigate("WorkShopDetailUC", paras);
                _logger.Info("监控模块跳转显示车间详情模块");
            } catch (Exception ex) {
                _logger.Error("监控模块显示车间详情出错:", ex);
            }

        }

        #endregion

        #region INavigationAware接口
        /// <summary>
        /// 接收参数:当页面被导航到（即成为活动页面）时触发，用于初始化数据或执行页面加载逻辑
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnNavigatedTo(NavigationContext navigationContext) {
            if (navigationContext.Parameters.ContainsKey("AccountInfoModel")) {
                AccountInfoModel = navigationContext.Parameters.GetValue<AccountInfoModel>("AccountInfoModel");
            }
        }
        /// <summary>
        /// 是否重用实例:决定是否复用当前页面实例（避免重复创建），通常用于优化多实例场景的性能
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public bool IsNavigationTarget(NavigationContext navigationContext) {
            return true;
        }
        /// <summary>
        /// 当页面即将离开（不再是活动页面）时触发，用于清理资源或保存状态
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnNavigatedFrom(NavigationContext navigationContext) {

        }
        #endregion
    }
}
